/*
 * Project: Sudoku Explainer
 * Copyright (C) 2006-2007 Nicolas Juillerat
 * 
 * Project: Sudoku Hint Engine for Android
 * Copyright (C) 2010-2013 Emanuel Moecklin
 * 
 * Available under the terms of the Lesser General Public License (LGPL)
 */
package com.onegravity.sudoku.solver.rules.uniqueness;

import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import com.onegravity.sudoku.solver.HintResource;
import com.onegravity.sudoku.solver.HintType;
import com.onegravity.sudoku.solver.R;
import com.onegravity.sudoku.solver.core.Rule;
import com.onegravity.sudoku.solver.data.Cell;
import com.onegravity.sudoku.solver.data.ImmutableCell;
import com.onegravity.sudoku.solver.data.Region;
import com.onegravity.sudoku.solver.util.HtmlLoader;
import com.onegravity.sudoku.solver.util.ValuesFormatter;

public class Bug3Hint extends BugHint implements Rule {

	private static final long serialVersionUID = -8556586196495399230L;
	
	private final Cell[] bugCells;
    private final Cell[] nakedCells;
    private final Map<Cell, BitSet> extraValues;
    private final BitSet allExtraValues;
    private final BitSet nakedSet;
    private final Region region;

    public Bug3Hint(Map<Cell, BitSet> removablePotentials,
            Cell[] bugCells, Cell[] nakedCells, Map<Cell, BitSet> extraValues,
            BitSet allExtraValues, BitSet nakedSet, Region region) {
        super(removablePotentials);
        this.bugCells = bugCells;				// cells with extra candidates
        this.extraValues = extraValues;			// Map bugCells --> extra candidates
        this.allExtraValues = allExtraValues;	// BitSet of extra candidates
        this.nakedCells = nakedCells;			// cells that form the naked subset (without the bug cells)
        this.nakedSet = nakedSet;				// BitSet with naked subset candidates
        this.region = region;
    }

    @Override
    public Collection<Cell> getSelectedCells(HintType hintType) {
    	return (hintType!=HintType.SMALL_CLUE) ? Arrays.asList(bugCells) : null;
    }

    @Override
    public Map<Cell, BitSet> getSelectedPotentials(HintType hintType, int viewNum) {
    	return Collections.emptyMap();
    }

    @Override
    public Map<Cell, BitSet> getAddedPotentials(HintType hintType, int viewNum) {
        Map<Cell, BitSet> result = new HashMap<Cell, BitSet>();
        for (Cell cell : bugCells) {
            BitSet innerNaked = (BitSet)nakedSet.clone();
            innerNaked.and(extraValues.get(cell));
            result.put(cell, innerNaked);
        }
        return (hintType==HintType.HINT) ? extraValues : null;
    }

    @Override
    public Map<Cell, BitSet> getSecondarySelectedPotentials(HintType hintType, int viewNum) {
        Map<Cell, BitSet> result = new HashMap<Cell, BitSet>();
        for (Cell cell : nakedCells) {
        	BitSet cand = (BitSet) cell.getPotentialValues().clone();
        	cand.and(nakedSet);
            result.put(cell, cand);
        }
        return (hintType==HintType.HINT) ? result : null;
    }

    @Override
    public Map<ImmutableCell, BitSet> getRemovedPotentials(HintType type) {
        return (type==HintType.HINT) ? super.getRemovedPotentials(type) : null;
    }

    @Override
    public double getDifficulty() {
        double toAdd = (nakedSet.cardinality() - 1) * 0.1; // Pair=0.1, Quad=0.3
        return 5.7 + toAdd;
    }

    @Override
    public Region[] getRegions(HintType type) {
    	return (type==HintType.HINT) ? new Region[] {this.region} : null;
    }

    @Override
    protected HintResource getResource() {
    	return HintResource.BUG_3;
    }

    @Override
    protected int getType() {
    	return 3;
    }

    @Override
    protected String getAppendixString() {
    	return Cell.toString(bugCells) + " " + HintResource.getString(R.string.on) + " " + ValuesFormatter.formatValues(nakedSet, ", "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    }

    @Override
    public String getHintHtml(HintType hintType) {
        String andString = HintResource.getString(R.string.and);
        String orString = HintResource.getString(R.string.or);
        String result = HtmlLoader.loadHtml(HintResource.BUG_3.hint(hintType));
        String andExtraValues = ValuesFormatter.formatValues(allExtraValues, " " + andString + " "); //$NON-NLS-1$ //$NON-NLS-2$
        String andBugCells = ValuesFormatter.formatCells(bugCells, " " + andString + " "); //$NON-NLS-1$ //$NON-NLS-2$
        String orBugCells = ValuesFormatter.formatCells(bugCells, " " + orString + " "); //$NON-NLS-1$ //$NON-NLS-2$
        String orExtraValues = ValuesFormatter.formatValues(allExtraValues, " " + orString + " "); //$NON-NLS-1$ //$NON-NLS-2$
        int[] namesRes = {R.string.hint_pair, R.string.hint_triple, R.string.hint_quad, R.string.hint_set5, R.string.hint_set6, R.string.hint_set7};
        String setName = HintResource.getString(namesRes[nakedSet.cardinality() - 2]);
        String andOtherCells = ValuesFormatter.formatCells(nakedCells, " " + andString + " "); //$NON-NLS-1$ //$NON-NLS-2$
        String andNakedValues = ValuesFormatter.formatValues(nakedSet, " " + andString + " "); //$NON-NLS-1$ //$NON-NLS-2$
        String regionName = region.toFullString();
        return HtmlLoader.format(result, andExtraValues, andBugCells, orBugCells, orExtraValues, setName, andOtherCells, andNakedValues, regionName);
    }

}
